home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Programming Sound Cards
/
Programming Sound Cards.iso
/
sound_57
/
sampler.inc
< prev
next >
Wrap
Text File
|
1995-01-01
|
43KB
|
1,451 lines
{ Utility procedures for sampler.pas}
{$f+}
procedure samplerexit; {$f-}
{ incase graphics mode, restore text screen before error message is given
also restores keyboard interrupt on abort}
begin {samplerexit}
mem[0 : $417] := mem[0 : $417] And $fc; {shift off}
restorecrtmode;
exitproc:=exitsave;
if showerrormessage then
writeln('Exit due to internal error!');
if customkbd then
restore;
end; {samplerexit}
function index(position:longint):longint;
{ calculates buffer array index for given screen position}
begin {index}
if zoom then
index:=viewleft+position - plotxoffset
else
index:=Round((position - plotxoffset)
/ (getmaxx - 2 * plotxoffset) * bufflength);
end;{index}
function scaleord(index:longint):integer;
{ calculates screen position for indexth position in buffer array}
begin {scaleord}
if zoom then
scaleord:=index-viewleft+plotxoffset
else
scaleord:= Round(index / bufflength * (getmaxx - 2 * plotxoffset)
+ plotxoffset); {move to end of read data}
end; {scaleord}
Function keypress : Boolean;
{ assumes custom keyboard service is installed. checks if a key has been
pressed and released}
Begin
If kbdflag > 0 Then
Case keyval Of
42 : mem[0 : $417] := mem[0 : $417] Or 2; {lshift down}
54 : mem[0 : $417] := mem[0 : $417] Or 1; {rshift down}
170 : mem[0 : $417] := mem[0 : $417] And $fd; {lshift release}
182 : mem[0 : $417] := mem[0 : $417] And $fe; {rshift release}
End; {case}
keypress := (kbdflag > 0) And (keyval < 128);
End; {keypress}
Function get_inc(tune : Integer; c : Char) : Integer;
{ returns a fractional increment value for a given key based on 12th root
of 2}
Begin
get_inc := Round(tune * Exp(kbdmap[c] * 0.057762265));
{= (12th root of 2)^kbdmap[c] * tune}
End; {get_inc}
Procedure display_title(title_string:string; font, fontsize,
bcolor,color:word);
{ displays nice big bold title}
Begin
settextstyle(font, horizdir, fontsize);
settextjustify(centertext, toptext);
panel(getmaxx Div 2, 1, getmaxx-cornersize*2, Round(textheight(titlestring) * 1.1),
bcolor);
selectcolor(color);
outtextxy(getmaxx Div 2, - 4, title_string);
End; {display_title}
Procedure display_pointers(leftord,rightord,loopord:longint;
leftshow,rightshow,loopshow:boolean);
{ displays up to 3 pointers}
Begin
if leftshow and (leftord>=viewleft) and (leftord<=viewright) then
putimage(scaleord(leftord) - arrowxoff, arrowlowy, uparrowp^, xorput);
if rightshow and (rightord<=viewright) and (rightord<=viewright) then
putimage(scaleord(rightord) - arrowxoff, arrowlowy, uparrowp^, xorput);
if loopshow and (loopord>=viewleft) and (loopord<=viewright) then
putimage(scaleord(loopord) - arrowxoff, arrowhighy, downarrowp^, xorput);
End; {display_pointers}
Procedure highlight_directory_entry(fileno : Integer; extension:boolean;
highlight : Boolean);
{ highlights the currently selected file or restores if highlight=false
if extension=true then the file extension is shown also}
Var j, x, y : Integer;
str1 : String;
Begin
settextstyle(smallfont, horizdir, 4);
settextjustify(lefttext, toptext);
str1:=copy(bigemptystring,1,dirnamefieldwidth);
j := pos('.', dir[fileno]);
if extension or (j=0) then
j:=succ(length(dir[fileno]));
If highlight Then
Begin
selectcolor(dirhcolor);
selectfillstyle(solidfill, dircolor);
End
Else
Begin
selectcolor(dircolor);
selectfillstyle(solidfill, dirbcolor);
End;
x := cornersize
+ (Pred(fileno) Mod dirnamesperline) * textwidth(str1);
y := directoryyoff
+ Pred(fileno) Div dirnamesperline * textheight(' ');
bar(x, y+1, x + textwidth(Copy(str1, 1, 8)),
y + textheight(' ') );
outtextxy(x, y, Copy(dir[fileno], 1, Pred(j)));
End; {highlight_directory_entry}
Procedure getdirectory(Var dir : directory_type; pattern : String);
{read file names in current directory matching pattern to dir}
Var dirinfo : searchrec;
fileno,i : Integer;
Begin
findfirst(path+'\'+pattern, 0, dirinfo);
fileno := 1;
While doserror = 0 Do
Begin
dir[fileno] := dirinfo.name;
i:=pos('.',dir[fileno]);
if i in [1..8] then
dir[fileno]:=copy(copy(dir[fileno],1,pred(i))+' ',1,8)+
copy(dir[fileno],i,4); {right justify extension}
Inc(fileno);
findnext(dirinfo);
End;
dir[fileno] := ''; {mark end of list}
End; {getdirectory}
Procedure showdirectory(extension:string);
{ displays files with extension in current directory}
var i,j,k:integer;
Begin
settextstyle(smallfont, horizdir, 5);
settextjustify(lefttext, toptext);
fill_background(dirbcolor,solidfill,cornersize);
selectcolor(dircolor);
getdirectory(dir, '*.'+extension);
if extension='*' then
extension:='All';
outtextxy(cornersize, 0, extension+' files on ' +
path);
directoryyoff:=round(textheight(' ')*1.3);
i := 1;
While (dir[i]<>'') and (dir[Succ(i)] <> '') Do {sort dir}
Begin
j := Succ(i);
While dir[j] <> '' Do
Begin
If dir[j] < dir[i] Then {name out of sequence}
Begin
str1 := dir[j];
For k := Pred(j) Downto i Do {shift names down list}
dir[Succ(k)] := dir[k];
dir[i] := str1; {insert name in correct place}
End;
j := Succ(j);
End;
i := Succ(i);
End;
str1 := '';
For i := 1 To dirnamefieldwidth Do
str1 := str1 + ' ';
i := 1;
While dir[i] <> '' Do
Begin
highlight_directory_entry(i, (extension='All'),False);
i := Succ(i);
End;
filesavail := Pred(i);
settextstyle(smallfont, horizdir, 4);
settextjustify(lefttext, toptext);
Str(diskfree(0) shr 10, str1);
outtextxy(cornersize,
directoryyoff+(filesavail div dirnamesperline +1)
*textheight(' '),' With ' + str1 + ' k free');
End; {showdirectory}
procedure pickfile(extension:string; var pick:string);
{ shows directory list, then allows file selection by mouse or naming
specifically}
var j:integer;
c:char;
cp:clickboxtypep;
dp:dialogentryp;
manual:boolean;
function strip(s:string):string;
{ strips spaces from string and converts to lower case}
var i:integer;
begin
i:=pos(' ',s);
while i>0 do
begin
delete(s,i,1);
i:=pos(' ',s);
end;
for i:=1 to length(s) do
if s[i] in ['A'..'Z'] then
s[i]:=chr(ord(s[i])+ord('a')-ord('A'));
strip:=s;
end; {strip}
function selection:integer;
{ determines which (if any) file bar was selected}
var boxwidth,boxheight,sel:integer;
begin {selection}
boxwidth:=textwidth(copy(bigemptystring,1,dirnamefieldwidth));
boxheight:=textheight(' ');
if (mousex>cornersize) and
(mousex-cornersize<boxwidth*dirnamesperline) and
((mousex -cornersize) mod boxwidth
< textwidth(copy(bigemptystring,1,8))) and
(mousey>directoryyoff) and
(mousey-directoryyoff
<(pred(filesavail) div dirnamesperline +1)*boxheight) then
begin
sel:=(mousex-cornersize) div boxwidth +
((mousey-directoryyoff) div boxheight )*dirnamesperline+1;
if sel>filesavail then
selection:=-1
else
selection:=sel;
end
else
selection:=-1;
end; {selection}
begin {pickfile}
mousearrowoff;
showdirectory(extension);
settextstyle(defaultfont,horizdir,1);
selectcolor(dialogcolor);
selectfillstyle(solidfill,dialogbcolor);
new(cp);
with cp^ do
begin
ttype:=_text;
title:='Specify input file';
x:=0;
y:=0;
next:=nil;
end;
draw_clicklist(cp,cornersize,getmaxy-textheight(' ')*2,clickbcolor,clickcolor);
mousearrowon;
j:=-1;
settextstyle(smallfont, horizdir, 4);
settextjustify(lefttext, toptext);
manual:=false;
repeat
repeat
c:=trackmouse;
until (mousekeys>0) or (c in [^c,^m]);
if c=^m then
manual:=true;
if mousekeys>1 then
begin
pick:='';
j:=0;
end
else
if mousekeys=1 then
begin
settextstyle(defaultfont,horizdir,1);
if click_selection(cp,cornersize,getmaxy-textheight(' ')*2)>-1 then
begin
draw_clicklist(cp,cornersize,getmaxy-textheight(' ')*2,clickcolor,
clickbcolor);
manual:=true;
end
else
begin
settextstyle(smallfont,horizdir,4);
j:=selection;
end;
end
else
j:=-1;
until (j>-1) or manual or (c=^c);
mousearrowoff;
if not manual and (j>0) and (dir[j]<>'') then
begin
highlight_directory_entry(j, (extension='*'),true);
pick:=dir[j];
repeat
j:=pos(' ',pick);
if j>0 then
delete(pick,j,1);
until j=0;
end;
if manual then
Begin
new(dp);
with dp^ do
begin
title:='Name of input file (.'+extension+') (' + #17 +'--+ to skip):';
argtype:=_string;
ssize:=30;
stringresult:='';
next:=nil;
end;
settextstyle(defaultfont,horizdir,1);
dialog_box(dp,dialogbcolor,dialogcolor,false);
pick:=dp^.stringresult;
dispose(dp);
if (pick<>'') and (pos('.',pick)=0) then
pick:= strip(pick + '.'+extension);
End;
mousearrowon;
dispose(cp);
end; {pickfile}
procedure cut_region(cutleft,cutright:longint);
{ clears area of buffer following a cut operation}
begin {cut_region}
fillchar(buffer^[cutleft],cutright-cutleft+1,127);
end; {cut_region}
procedure set_bounds;
{ recalculates boundary values for current pointer positions}
begin {set_bounds}
{$ifdef pwm}
bufstart := Ofs(bufferw^[leftord]);
bufend := Ofs(bufferw^[rightord]);
bufloop := Ofs(bufferw^[loopord]);
{$else}
bufstart := Ofs(buffer^[leftord]);
bufend := Ofs(buffer^[rightord]);
bufloop := Ofs(buffer^[loopord]);
{$endif}
end; {set_bounds}
procedure move_pointers(d1,d2,d3:integer);
{ move pointers by given delta values}
var lefttemp,righttemp,looptemp:longint;
unlimited:boolean;
Begin
lefttemp:=leftord;
righttemp:=rightord;
looptemp:=loopord;
leftord:=leftord+index(d1-viewleft+plotxoffset);
rightord:=rightord+index(d2-viewleft+plotxoffset);
loopord:=loopord+index(d3-viewleft+plotxoffset);
If leftord < 0 Then
leftord := 0;
If rightord > bufflength Then
rightord := bufflength;
If rightord < getmaxx div 5 Then
rightord := getmaxx div 5;
If leftord >= rightord-getmaxx div 5 Then
leftord := rightord - getmaxx div 5;
If loopord > rightord -getmaxx div 5 Then {don't let arrows overlap}
loopord := rightord - getmaxx div 5;
If loopord < leftord Then
loopord := leftord;
display_pointers(lefttemp,righttemp,looptemp,(lefttemp<>leftord),
(righttemp<>rightord),(looptemp<>loopord)); {erase pointers}
display_pointers(leftord,rightord,loopord,(lefttemp<>leftord),
(righttemp<>rightord),(looptemp<>loopord)); {show pointers}
End; {move_pointers}
procedure load_sound_file(fn : String; leftlimit,rightlimit:longint;
mix:boolean);
{ reads given sound file to the buffer. limits determine edges of allowed
region for loading. if sound file won't fit, it will be truncated.
if mix is true, then new file will be mixed with old data}
Var i,j,k : longint;
f : File;
lastdp,dp,dialoghead:dialogentryp;
reducecut,reduceoriginal,reduceall:boolean;
cutshift,originalshift:byte;
offset:integer;
storagep:pointer;
Begin
if (fn[1]<>'\') and (fn[2]<>':') then
Assign(f, path+'\'+fn)
else
Assign(f, fn);
{$i-}
Reset(f);
{$i+}
If IoResult = 0 Then
Begin
i:=0;
for i:=1 to filesize(f) div (blocksize div 128) do {read whole blocks}
BlockRead(f, bufferw^[pred(i) * blocksize], blocksize shr 7);
for j:=1 to filesize(f) mod (blocksize div 128) do {read what's left}
BlockRead(f, bufferw^[i * blocksize+pred(j)*128], 1);
loopord := bufferw^[2] + longint(bufferw^[3]) * 256 + plotxoffset;
i := bufferw^[0] + longint(bufferw^[1]) * 256; {get sample size}
j:=rightlimit-leftlimit;
if i<j then
j:=i; {copy size is smallest of file size and cutbox size}
if leftord>leftlimit then
leftord:=leftlimit;
if cutboxactive then
begin
if j+leftlimit>rightord then
rightord:=j+leftlimit;
end
else
rightord := j; {move to end of read data}
if not mix then
Move(bufferw^[4], buffer^[leftlimit],j)
{shift work buffer to buffer}
else
begin
dialoghead:=nil;
new(dp);
with dp^ do
begin
title:='Reduce amplitude of cut file to fit (halve)?';
argtype:=_boolean;
booleanresult:=true;
next:=nil;
end;
add_dialogentry(dp,lastdp,dialoghead);
new(dp);
with dp^ do
begin
title:='Reduce amplitude of original to fit (halve)?';
argtype:=_boolean;
booleanresult:=true;
next:=nil;
end;
add_dialogentry(dp,lastdp,dialoghead);
new(dp);
with dp^ do
begin
title:='If reducing original, reduce whole thing?';
argtype:=_boolean;
booleanresult:=true;
next:=nil;
end;
add_dialogentry(dp,lastdp,dialoghead);
settextstyle(defaultfont,horizdir,1);
dialog_box(dialoghead,dialogbcolor,dialogcolor,true);
reducecut:=dialoghead^.booleanresult;
reduceoriginal:=dialoghead^.next^.booleanresult;
reduceall:=dialoghead^.next^.next^.booleanresult;
dispose(dialoghead);
cutshift:=ord(reducecut);
originalshift:=ord(reduceoriginal);
settextstyle(defaultfont,horizdir,1);
display_message('Calculating...',
dialogbcolor,dialogcolor,storagep,true);
if reduceoriginal and reduceall then
begin
for i:=0 to leftlimit-1 do
buffer^[i]:=buffer^[i] shr 1+64;
for i:=leftlimit+j+1 to bufflength do
buffer^[i]:=buffer^[i] shr 1+64;
end;
offset:=integer(128)-128 shr originalshift-128 shr cutshift;
k:=leftlimit-4;
for i:=leftlimit to leftlimit+j do
{$r-} buffer^[i]:=integer(buffer^[i] shr originalshift)
+bufferw^[i-k] shr cutshift+offset;
{$ifdef debug}
{$r+} { switch range checking off above means overrange produces distortion}
{$endif}
display_message('Calculating...',
dialogbcolor,dialogcolor,storagep,false);
end;
set_bounds;
Close(f); {must do this incase another read (assign) later}
workfile := fn;
End
Else
Begin
beep;
default_sound_file:='';
workfile:='';
leftord := 0;
rightord := bufflength;
loopord := leftord;
set_bounds;
new(dp);
dp^.next:=nil;
dp^.title:='Sound file '+workfile+' not found';
dp^.argtype:=_none;
settextstyle(defaultfont,horizdir,1);
dialog_box(dp,dialogbcolor,dialogcolor,true);
dispose(dp);
End;
End; {load_sound_file}
Procedure select_system(c : Char);
{ selects speed params for xt, xt turbo, at, at turbo}
Begin
Case c Of
'X' :
Begin
tconstant := round(1.19318e3/14); {timer constant for 14KHz }
systemname := 'XT';
end;
'T' :
Begin
tconstant := round(1.19318e3/22); {timer constant for 22KHz }
systemname := 'XT turbo';
end;
'A' :
Begin
tconstant := round(1.19318e3/30); {timer constant for 30kHz }
systemname := 'AT';
end;
'U' :
Begin
tconstant := round(1.19318e3/45); {timer constant for 45kHz }
systemname := 'AT turbo';
end;
End; {case}
If c In ['X', 'T', 'A', 'U'] Then
Begin
incdef:=round(default_samplerate*(tconstant/1.1938e3)*256)+1;
sysspeed:=incdef; {incase pwm, this indicates system speed factor}
{$ifdef pwm}
if c in ['X','T'] then
tconstant:=round(1.19318e3/16)
else
tconstant := round(1.19318e3/20);
incdef:=round(default_samplerate*(tconstant/1.1938e3)*256)+2;
{$endif pwm}
increment := incdef;
tune := increment;
crotchet:=round(60.0/tconstant*100);
{tinterval for a crotchet}
modulus:=round(0.25*1.19318e6/crotchet/tconstant);
{set duration decrement rate for crotchet=.25 sec}
End;
End; {select_system}
function get_daport(s:string):word;
{ sets d/a port from string}
var i,j:integer;
begin {get_daport}
if (s='LPT2') or (s='lpt2') then
get_daport:=lpt2
else
if (s='LPT3') or (s='lpt3') then
get_daport:=lpt3
else
if (s='LPT1') or (s='lpt1') then
get_daport:=lpt1
else
begin
val(s,j,i);
if i>0 then
begin
closegraph;
writeln('Error in port address from ',cnffilename,' => ',s);
halt;
end;
get_daport:=j;
end;
end; {get_daport}
procedure display_status;
{ displays status and version info in a title box}
var dp,dialoghead,lastdialogentry:dialogentryp;
begin {display_status}
dialoghead:=nil;
if getmaxy>200 then
begin
new(dp);
with dp^ do
begin
title:=' '+titlestring;
argtype:=_none;
add_dialogentry(dp,lastdialogentry,dialoghead);
end;
end;
new(dp);
with dp^ do
begin
title:='Current path:';
argtype:=_string;
nulvalid:=false;
stringresult:=path;
ssize:=length(titlestring)-11;
add_dialogentry(dp,lastdialogentry,dialoghead);
end;
new(dp);
with dp^ do
begin
title:='Current sound file:'+copy(bigemptystring,1,
length(titlestring)-length(workfile)-16)+workfile;
argtype:=_none;
add_dialogentry(dp,lastdialogentry,dialoghead);
end;
new(dp);
with dp^ do
begin
title:='Instrument type:';
argtype:=_string;
nulvalid:=false;
stringresult:=default_kbdmap;
ssize:=6;
add_dialogentry(dp,lastdialogentry,dialoghead);
end;
new(dp);
with dp^ do
begin
title:='Sytem type:';
argtype:=_string;
nulvalid:=false;
stringresult:=systemname;
ssize:=8;
add_dialogentry(dp,lastdialogentry,dialoghead);
end;
new(dp);
with dp^ do
begin
title:='Key release:';
argtype:=_boolean;
booleanresult:=releasestate;
add_dialogentry(dp,lastdialogentry,dialoghead);
end;
new(dp);
with dp^ do
begin
title:='Loop mode:';
argtype:=_boolean;
booleanresult:=loop;
add_dialogentry(dp,lastdialogentry,dialoghead);
end;
new(dp);
with dp^ do
begin
title:='Auto timer:';
argtype:=_boolean;
booleanresult:=timer;
add_dialogentry(dp,lastdialogentry,dialoghead);
end;
{$ifdef sample}
new(dp);
with dp^ do
begin
title:='Trigger level:';
argtype:=_integer;
integerresult:=trigger;
add_dialogentry(dp,lastdialogentry,dialoghead);
end;
new(dp);
with dp^ do
begin
title:='Sample rate:';
argtype:=_integer;
integerresult:=samplerate;
add_dialogentry(dp,lastdialogentry,dialoghead);
end;
{$endif}
new(dp);
with dp^ do
begin
title:='D/A port:';
argtype:=_string;
stringresult:=default_daport;
nulvalid:=false;
ssize:=4;
add_dialogentry(dp,lastdialogentry,dialoghead);
end;
if getmaxy<300 then
begin
setusercharsize(14,10,100,101);
settextstyle(smallfont,horizdir,usercharsize);
end
else
settextstyle(defaultfont,horizdir,1);
dialog_box(dialoghead,dialogbcolor,dialogcolor,true);
dp:=dialoghead;
if getmaxy>200 then
dp:=dp^.next;
path:=dp^.stringresult;
dp:=dp^.next;
dp:=dp^.next;
default_kbdmap:=dp^.stringresult;
dp:=dp^.next;
systemname:=dp^.stringresult;
while (systemname[1]=' ') and (length(systemname)>1) do
delete(systemname,1,1);
case upcase(systemname[1]) of
'X': if (length(systemname)>4) and (systemname[5]<>' ') then
select_system('T')
else
select_system('X');
'A': if (length(systemname)>4) and (systemname[5]<>' ') then
select_system('U')
else
select_system('A');
end; {case}
dp:=dp^.next;
releasestate:=dp^.booleanresult;
dp:=dp^.next;
loop:=dp^.booleanresult;
dp:=dp^.next;
timer:=dp^.booleanresult;
{$ifdef sample}
dp:=dp^.next;
trigger:=dp^.integerresult;
dp:=dp^.next;
samplerate:=dp^.integerresult;
{$endif}
dp:=dp^.next;
default_daport:=dp^.stringresult;
daout:=get_daport(default_daport);
dispose_dialog(dialoghead);
end; {display_status}
Procedure initialise;
{ initialise global variables etc}
Var i,j:integer;
Begin
WriteLn;
WriteLn(' ', titlestring);
WriteLn;
WriteLn;
Assign(cnffile, cnffilename);
{$i-} Reset(cnffile); {$i+}
If IoResult <> 0 Then
Begin
WriteLn('Error opening configuration file ', cnffilename);
Halt;
End;
songfilename:='';
new(buffer); {create sound storage buffer}
new(bufferw); {create buffer overflow space}
new(dummy); {creat overflow area AFTER bufferw}
ReadLn(cnffile, path);
ReadLn(cnffile, default_sound_file);
ReadLn(cnffile, default_system);
ReadLn(cnffile, default_daport);
ReadLn(cnffile, default_kbdmap);
if path='' then
path:='.';
quickexit:=false;
filesavail := 0;
zoom:=false;
goodbye:=false;
loop := False;
timer := False;
song:=false;
trigger := 200; {set trigger to reasonable level}
select_system(Upcase(default_system));
tinterval:=crotchet; {set note duration to crotchet (if timer used)}
copying := False;
songspeed:=1.0; {defauult song speed}
kbdmode:=false;
kbdflag := 0;
keyval := 0;
release:=true;
releasestate := True; {sensitive to key release}
cutboxactive:=false;
cutactive:=false;
bufflen:=bufflength;
graphdriver := detect;
If (registerbgifont(@triplexfontproc) < 0) Or
(registerbgifont(@smallfontproc) < 0) Then
Begin
WriteLn('Error loading font');
Halt;
End;
If (registerbgidriver(@hercdriverproc) < 0) Or
(registerbgidriver(@cgadriverproc) < 0) Or
(registerbgidriver(@egavgadriverproc) < 0) Then
Begin
WriteLn('Error loading driver');
Halt;
End;
initgraph(graphdriver, graphmode, 'c:\language\turbop4\grf');
settextstyle(smallfont,horizdir,4);
wavescale := 1 - Ord(getmaxy > 300) + 2;
if getmaxy >200 then
wavebottom := getmaxy-textheight(' ')*9
else
wavebottom := getmaxy-textheight(' ')*6;
wavetop:=wavebottom-255 div wavescale;
arrowlowy := wavebottom + 2;
arrowhighy := wavebottom - 256 Div wavescale - arrowysize - 2;
drawpoly(arrowpoints, uparrowshape); {draw up arrow}
fillpoly(arrowpoints, uparrowshape); {fill " }
GetMem(uparrowp, imagesize(0, 0, arrowxsize, arrowysize));
getimage(0, 0, arrowxsize, arrowysize, uparrowp^); {save arrow image}
drawpoly(arrowpoints, downarrowshape); {draw down arrow on the right}
fillpoly(arrowpoints, downarrowshape);
GetMem(downarrowp, imagesize(0, 0, arrowxsize, arrowysize));
getimage(100, 0, 100 + arrowxsize, arrowysize, downarrowp^); {save image}
cleardevice;
initpointer;
settextstyle(smallfont, horizdir, 4);
settextjustify(lefttext, toptext);
for j:=1 to noheadings do {make storage for image under menu bars}
for i:=2 to maxverticalbars do
if menustructure[j].entry[i].selection<>inactive then
GetMem(menustorage[j].entry[i],
imagesize(0,0,(getmaxx-cornersize*2) div noheadings,
round(textheight(' ')*1.5)-1));
fill_background(screencolor,interleavefill,cornersize);
display_title(titlestring,triplexfont,4,panelcolor,titlecolor);
settextstyle(smallfont, horizdir, 4);
settextjustify(lefttext, centertext);
dirnamesperline := (getmaxx - cornersize * 2)
Div (dirnamefieldwidth * textwidth(' '));
panel(getmaxx div 2,getmaxy div introyoff-textheight(' '),
getmaxx-cornersize*2,textheight(' ')*8,panelcolor);
settextstyle(defaultfont, horizdir, 1);
selectcolor(black);
daout:=get_daport(default_daport);
{$ifndef pwm}
outtextxy(cornersize,getmaxy div introyoff,' D/A converter is on '
+default_daport);
{$endif pwm}
outtextxy(cornersize, getmaxy Div introyoff + textheight(' ') * 2,
' Sound files path is ' + path);
If (default_kbdmap = 'guitar') Or (default_kbdmap = 'GUITAR') Then
Begin
default_kbdmap := 'guitar';
kbdmap := kbdmapguitar;
End;
If default_kbdmap <> 'guitar' Then
Begin
default_kbdmap := 'piano ';
kbdmap := kbdmappiano;
End;
outtextxy(cornersize, getmaxy Div introyoff + textheight(' ') * 4,
' Using keyboard map for ' + default_kbdmap);
outtextxy(cornersize, getmaxy Div introyoff + textheight(' ') * 6,
' Reading default sound file ' + default_sound_file+'...');
mousearrowon;
cut_region(index(plotxoffset),index(getmaxx-plotxoffset)); {clear buffer}
leftord:=0;
rightord:=0;
loopord:=0;
load_sound_file(default_sound_file,index(plotxoffset),
index(getmaxx-plotxoffset),false);
viewleft:=index(plotxoffset);
viewright:=index(getmaxx-plotxoffset);
samplerate:=default_samplerate;
i:=0;
display_status;
mousearrowoff;
settextstyle(defaultfont,horizdir,1);
tuningcp:=nil;
new(cp);
cp^.ttype:=_text;
cp^.x:=0;
cp^.y:=0;
cp^.title:=#25;
add_clickboxentry(cp,lastcp,tuningcp);
new(cp);
cp^.ttype:=_figure;
cp^.x:=textwidth(' ');
cp^.y:=0;
cp^.numpoints:=tuningshapepoints;
cp^.polypoints:=@tuninglshape;
cp^.fill:=true;
add_clickboxentry(cp,lastcp,tuningcp);
new(cp);
cp^.ttype:=_text;
cp^.x:=textwidth(' ');
cp^.y:=0;
cp^.title:=#17;
add_clickboxentry(cp,lastcp,tuningcp);
new(cp);
cp^.ttype:=_text;
cp^.x:=textwidth(' ');
cp^.y:=0;
cp^.title:=#16;
add_clickboxentry(cp,lastcp,tuningcp);
new(cp);
cp^.ttype:=_figure;
cp^.x:=textwidth(' ');
cp^.y:=0;
cp^.numpoints:=tuningshapepoints;
cp^.polypoints:=@tuningrshape;
cp^.fill:=true;
add_clickboxentry(cp,lastcp,tuningcp);
new(cp);
cp^.ttype:=_text;
cp^.x:=textwidth(' ');
cp^.y:=0;
cp^.title:=#24;
add_clickboxentry(cp,lastcp,tuningcp);
new(cp);
cp^.ttype:=_text;
cp^.x:=textwidth(' ');
cp^.y:=0;
cp^.title:='Reset';
add_clickboxentry(cp,lastcp,tuningcp);
new(cp);
cp^.ttype:=_text;
cp^.x:=textwidth(' ');
cp^.y:=-textheight(' ')*2;
cp^.title:='Tuning';
add_clickboxentry(cp,lastcp,tuningcp);
timercp:=nil;
new(cp);
cp^.ttype:=_figure;
cp^.x:=0;
cp^.y:=0;
cp^.numpoints:=tuningshapepoints;
cp^.polypoints:=@tuninglshape;
cp^.fill:=true;
add_clickboxentry(cp,lastcp,timercp);
new(cp);
cp^.ttype:=_text;
cp^.x:=textwidth(' ');
cp^.y:=0;
cp^.title:=#17;
add_clickboxentry(cp,lastcp,timercp);
new(cp);
cp^.ttype:=_text;
cp^.x:=textwidth(' ');
cp^.y:=0;
cp^.title:=#16;
add_clickboxentry(cp,lastcp,timercp);
new(cp);
cp^.ttype:=_figure;
cp^.x:=textwidth(' ');
cp^.y:=0;
cp^.numpoints:=tuningshapepoints;
cp^.polypoints:=@tuningrshape;
cp^.fill:=true;
add_clickboxentry(cp,lastcp,timercp);
new(cp);
cp^.ttype:=_text;
cp^.x:=textwidth(' ');
cp^.y:=-textheight(' ')*2;
cp^.title:=' Timer';
add_clickboxentry(cp,lastcp,timercp);
End; {initialise}
Procedure update_settings;
{ write settings on screen}
Var str1,str2 : String;
h : Integer;
Begin
settextstyle(smallfont,horizdir,4);
h:=textheight(' ')*3;
settextjustify(centertext, toptext);
selectcolor(black);
settextstyle(defaultfont, horizdir, 1);
panel(getmaxx Div 2, h - Round(textheight(' ') * 0.25), getmaxx -cornersize*2,
Round(textheight(' ') * 3.5),panelcolor);
outtextxy(getmaxx div 2,h,'Current status: ');
str1:='';
{$ifdef sample}
str(trigger,str2);
str1:=str1 + ' Trigger: '+str2;
{$endif}
settextjustify(lefttext, toptext);
outtextxy(cornersize, h +textheight(' '),str1+
' Path: ' + path +
' File: ' + workfile);
If loop Then
str1 := ' Loop mode: on'
Else
str1 := ' Loop mode: off';
If releasestate Then
str1 := str1 + ' Key release: on'
Else
str1 := str1 + ' Key release: off';
If timer Then
str1 := str1 + ' Auto timer: on'
Else
str1 := str1 + ' Auto timer: off';
{$ifdef sample}
str(samplerate,str2);
str1:=str1+ ' Sample rate: '+str2+'kHz';
{$endif}
outtextxy(cornersize, h + textheight(' ')*2, str1);
End; {update_settings}
procedure draw_wave;
{ draws wave box and wave form. clear indicates whether background should be
cleared first}
Var lasty, y,i : Integer;
ratio : Real;
begin {draw_wave}
ratio := (viewright-viewleft)/ (getmaxx - 2 * plotxoffset);
selectfillstyle(solidfill, black);
setlinestyle(solidln, 0, normwidth);
selectcolor(waveboxcolor);
bar(0, arrowlowy + arrowysize + 2, getmaxx, arrowhighy - 2);
rectangle(plotxoffset, wavebottom + 1, getmaxx - plotxoffset,
wavetop- 1);
rectangle(0, arrowlowy + arrowysize + 2, getmaxx, arrowhighy - 2);
selectcolor(wavecolor);
moveto(plotxoffset,wavebottom-buffer^[viewleft] div wavescale);
For i := 1 To getmaxx - plotxoffset*2 Do
lineto(i+plotxoffset,
wavebottom - buffer^[Round(i * ratio)+viewleft] Div wavescale);
display_pointers(leftord,rightord,loopord,true,true,true);
{$ifdef pwm}
scalewave;
{$endif {pwm}
end; {draw_wave}
Procedure update_display;
{ refresh graphics screen}
Begin
fill_background(screencolor,interleavefill,cornersize);
update_settings;
draw_wave;
draw_menu_headers;
settextstyle(defaultfont,horizdir,1);
draw_clicklist(tuningcp,cornersize,getmaxy-textheight(' ')*2,tuningbcolor,
tuningcolor);
draw_clicklist(timercp,getmaxx-cornersize-textwidth(' '),
getmaxy-textheight(' ')*2,timerbcolor,
timercolor);
End; {update_display}
PROCEDURE parsesong;
{ parse a Pianoman MUS file and save in song structure}
var storagep:pointer;
dp:dialogentryp;
BEGIN {parsesongfile}
songp := 1;
while not eof(fsong) and (songp<=maxbeats) do
begin
read(fsong,anote);
songarray[songp].note:=
Exp(((anote.octave-3)*12+anote.note-20)* 0.057762265); {convert pianoman
note to keyboard note
('Z'=>-12)}
if anote.note=13 then
songarray[songp].note:=-13;
songarray[songp].duration:=
round(anote.duration/1700*162/sysspeed*crotchet);
{scale duration also. note sysspeed takes
account of system speed dependence of Pianoman.
1700 is a typical pianoman crotchet length for
my at turbo, 162 is sysspeed for an at turbo}
inc(songp);
if songp>maxbeats then
begin
new(dp);
with dp^ do
begin
title:='Song too big - truncating';
argtype:=_none;
next:=nil;
end;
settextstyle(defaultfont,horizdir,1);
dialog_box(dp,dialogbcolor,dialogcolor,true);
dispose(dp);
end;
end;
songend := Pred(songp);
END; {parsesongfile}
procedure loadsong;
{ loads and parses a song file}
var storagep:pointer;
dp:dialogentryp;
begin
pickfile('MUS',songfilename);
mousearrowoff;
display_message('Loading '+songfilename,
dialogbcolor,dialogcolor,storagep,true);
if songfilename<>'' then
begin
if (songfilename[1]='\') or (songfilename[2]=':') then
Assign(fsong, songfilename)
else
Assign(fsong, path+'\'+songfilename);
{$i-}
Reset(fsong);
{$i+}
IF IOResult = 0 THEN
begin
parsesong;
Close(fsong); {must do this incase another read (assign) later}
end
else
begin
beep;
new(dp);
with dp^ do
begin
title:='File not found ('+songfilename+')';
argtype:=_none;
next:=nil;
end;
settextstyle(defaultfont,horizdir,1);
dialog_box(dp,dialogbcolor,dialogcolor,true);
dispose(dp);
songfilename:='';
end;
end;
display_message('Loading '+songfilename,
dialogbcolor,dialogcolor,storagep,false);
update_display;
mousearrowon;
end; {loadsong}
function arrow_selection:integer;
{ determines whether mouse is over a wave box arrow}
begin {arrow_selection}
if (mousex>=scaleord(leftord)-arrowxoff) and
(mousex<=scaleord(leftord)-arrowxoff+arrowxsize) and
(mousey>=arrowlowy) and (mousey<=arrowlowy+arrowysize) then
arrow_selection:=1
else
if (mousex>=scaleord(rightord)-arrowxoff) and
(mousex<=scaleord(rightord)-arrowxoff+arrowxsize) and
(mousey>=arrowlowy) and (mousey<=arrowlowy+arrowysize) then
arrow_selection:=2
else
if (mousex>=scaleord(loopord)-arrowxoff) and
(mousex<=scaleord(loopord)-arrowxoff+arrowxsize) and
(mousey>=arrowhighy) and (mousey<=arrowhighy+arrowysize) then
arrow_selection:=3
else
arrow_selection:=-1;
end; {arrow_selection}
procedure erase_cutbox;
{ erases cut box, restoring waveform}
var j:longint;
begin {erase_cutbox}
if cutboxactive then
begin
for j:=wavetop-1 to wavebottom+1 do
putpixel(scaleord(cutleft),j,getmaxcolor-getpixel(scaleord(cutleft),j));
if cutleft<>cutright then
for j:=wavetop-1 to wavebottom+1 do
putpixel(scaleord(cutright),j,getmaxcolor-getpixel(scaleord(cutright),j));
selectcolor(waveboxcolor);
line(scaleord(cutleft)-1,wavetop-1,scaleord(cutright)+1,wavetop-1);
line(scaleord(cutleft)-1,wavebottom+1,scaleord(cutright)+1,wavebottom+1);
end;
end; {erase_cutbox}
procedure draw_cutbox;
{ draws cut box}
var j:longint;
begin {draw_cutbox}
if cutboxactive then
begin
for j:=wavetop-1 to wavebottom+1 do
putpixel(scaleord(cutleft),j,getmaxcolor-getpixel(scaleord(cutleft),j));
if cutleft<>cutright then
for j:=wavetop-1 to wavebottom+1 do
putpixel(scaleord(cutright),j,getmaxcolor-getpixel(scaleord(cutright),j));
for j:=scaleord(cutleft)+1 to scaleord(cutright)-1 do
if (getmaxcolor>1) or odd(j) then
begin
putpixel(j,wavetop-1,getmaxcolor-getpixel(j,wavetop-1));
putpixel(j,wavebottom+1,getmaxcolor-getpixel(j,wavebottom+1));
end;
end;
end; {draw_cutbox}
procedure activate_menu_options(state:boolean);
{ enable/disable menu options requiring cut box}
begin {activate_menu_options}
menustructure[3].entry[2].visible:=state; {cut}
menustructure[3].entry[3].visible:=state; {copy}
menustructure[3].entry[6].visible:=state; {mirror}
menustructure[3].entry[7].visible:=state; {envelope}
menustructure[3].entry[8].visible:=state; {clear}
if not zoom then
menustructure[3].entry[9].visible:=state; {draw}
if cutactive and state then
begin
menustructure[3].entry[4].visible:=true; {paste}
menustructure[3].entry[5].visible:=true; {mix}
end
else
begin
menustructure[3].entry[4].visible:=false;
menustructure[3].entry[5].visible:=false;
end;
end; {activate_menu_options}
Procedure mirror_data;
{ mirror sample data between pointers}
Var temp : Byte;
i, j : longInt;
Begin
settextstyle(defaultfont,horizdir,1);
display_message('Calculating...',
dialogbcolor,dialogcolor,storagep,true);
j:=cutright;
For i := cutleft To (cutleft+cutright) shr 1 Do
Begin
temp := buffer^[i]; {temp}
buffer^[i] := buffer^[j];
buffer^[j] := temp;
dec(j);
End;
display_message('Calculating...',
dialogbcolor,dialogcolor,storagep,false);
End; {mirror_data}
Procedure scale_envelope;
{ scale sample data between points by an envelope formed by two end
factors}
Var j,i : longInt;
k1 : Real;
dp,dialoghead,lastdialogentry:dialogentryp;
Begin
dialoghead:=nil;
new(dp);
with dp^ do
begin
title:='Scale factor at left marker';
argtype:=_real;
decimalp:=2;
realresult:=1;
add_dialogentry(dp,lastdialogentry,dialoghead);
end;
new(dp);
with dp^ do
begin
title:='Scale factor at right marker';
argtype:=_real;
decimalp:=2;
realresult:=1;
add_dialogentry(dp,lastdialogentry,dialoghead);
end;
settextstyle(defaultfont,horizdir,1);
dialog_box(dialoghead,dialogbcolor,dialogcolor,true);
If not ((dialoghead^.realresult = 1) and (dialoghead^.next^.realresult=1))
Then
Begin
display_message('Calculating...',
dialogbcolor,dialogcolor,storagep,true);
For i := scaleord(cutleft) To Pred(scaleord(cutright)) Do
Begin
k1 := (dialoghead^.next^.realresult - dialoghead^.realresult)
/ (scaleord(cutright)-scaleord(cutleft))
* (i - scaleord(cutleft)+ plotxoffset) + dialoghead^.realresult;
For j := index(i) to index(i+1)-1 do
buffer^[j] := lo(Round((buffer^[j] - 128) * k1 + 128));
End;
display_message('Calculating...',
dialogbcolor,dialogcolor,storagep,false);
End;
dispose_dialog(dialoghead);
End; {scale_envelope}
Procedure write_data(fn:string; leftlimit,rightlimit:longint);
{ write sample data to disk file}
Var f : File;
i,j : longint;
dp:dialogentryp;
Begin
mousearrowoff;
settextstyle(defaultfont,horizdir,1);
display_message('Writing file, please wait...', dialogbcolor,
dialogcolor,storagep,true);
If pos('.', fn) = 0 Then
fn := fn + '.snd';
if (fn[1]<>'\') and (fn[2]<>':') then
Assign(f, path+'\'+fn)
else
assign(f,fn);
{$i-}
Rewrite(f);
{$i+}
If IoResult = 0 Then
Begin
Move(buffer^[leftlimit], bufferw^[4],rightlimit-leftlimit);
{shift up to make space for preamble}
bufferw^[0] := lo(rightlimit-leftlimit);
bufferw^[1] := hi(rightlimit-leftlimit);
bufferw^[2] := lo(loopord-leftlimit);
bufferw^[3] := hi(loopord-leftlimit);
i:=0;
For i := 1 to ((rightlimit-leftlimit) div 128)
div (blocksize div 128) do
blockwrite(f,bufferw^[pred(i)*blocksize],blocksize shr 7);
for j:=1 to ((rightlimit-leftlimit-1) div 128 +1)
mod (blocksize div 128) do
BlockWrite(f, bufferw^[i*blocksize+pred(j)*128], 1);
Close(f);
End
Else
Begin
beep;
new(dp);
dp^.next:=nil;
dp^.title:='Disk write error';
dp^.argtype:=_none;
mousearrowon;
dialog_box(dp,dialogbcolor,dialogcolor,true);
mousearrowoff;
dispose(dp);
End;
display_message('Writing file, please wait...', dialogbcolor,
dialogcolor,storagep,false);
mousearrowon;
End; {write_data}